Simple Bluetooth Low Energy (SBLE)

Registered Script Steps

Registered Calculation Functions

  1. SBLE_Version ( { versionFormat } )
  2. SBLE_Register ( selector )
  3. SBLE_StartScan ( { options } )
  4. SBLE_StopScan
  5. SBLE_Connect ( deviceID { ; options } )
  6. SBLE_Disconnect ( deviceID )
  7. SBLE_StartAdvertising ( { options } )
  8. SBLE_StopAdvertising
  9. SBLE_Get ( selector { ; deviceID } )
  10. SBLE_Set ( selector { ; deviceID } ; value )
  11. SBLE_SetLocalCharacteristic ( serviceUUID ; characteristicUUID ; value { ; format } )
  12. SBLE_GetLocalCharacteristic ( serviceUUID ; characteristicUUID { ; format } )
  13. SBLE_Subscribe ( deviceID ; serviceUUID ; characteristicUUID ; onNotify { ; format { ; timeout } } )
  14. SBLE_Read ( deviceID ; serviceUUID ; characteristicUUID { ; format { ; timeout } } )
  15. SBLE_Write ( deviceID ; serviceUUID ; characteristicUUID ; value { ; format { ; timeout } } )

API documentation

SBLE_Version ( { versionFormat } )

Returns version string of the Plug-In, formatted as requested by the parameter.

Parameter values for versionFormat

“short” To get just the version number. Default value.
“long” To get the Plug-In name followed by its version number.
“platform” To get the platform the code is currently running on.
“autoupdate” To get autoupdate compatible (comparable) version number.

Result

Returns requested version format or platform. If this function returns “?” then the Plug-In is not properly installed or FileMaker cannot load and activate it for some reason.

SBLE_Register ( selector )

Provides special functionality to operate with plugin serial numbers. Use this function to register or unregister the Plug-In, to get information about current registration state, or to invoke GUI providing basic registration information and purchase capabilities.

Parameter values for selector

SerialNumber Register given SerialNumber and return an error code.
EmailAddress Tries to activate with given email address and return an error code. Trial version is valid only after you confirm email
Hash Activate a serial number with a hash received from 24U. Used for offline activation.
“registrationWindow” Show the “Registration window” and return 0. Works only on desktop version.
“aboutWindow” Show the “About window” and return 0. Works only on desktop version.
“status” Return the actual registration state of the plugin: Demo, Demo expired, Trial, Trial Expired, Registered or Dead.
“unregister” Unregister all serial numbers related to the product and return an error code. Note: after this trial version days wont come back.
“info” Returns current plugin status and its registered serial numbers.
“activationChallenge” Returns generated challenge string. This string is sent to 24U.

Result

Returns zero. In case of error the function will return “?”. Use SBLE_Get( "lastError" ) to get the specific error code.

SBLE_StartScan ( { options } )

Scans for nearby devices. Use this when you want to use iPhone as a central device. Runs on asynchronous thread. Returns error if scan is already being performed or when Bluetooth is not available. Scan is automatically stopped on timeout. The result of scan get be viewed at any time using SBLE_Get ( "devices" ). Options is in the form of text field separated by ¶.

Optional parameters

Parameter Description Accepted values Default
“stopAfter” Halt scanning after this time (in seconds). Float or “never” 60
“minRSSI” Find devices whose signal is not weaker (lower) than provided value. It can be positive or negative double precision floating-point number. (Negative values are more common.) Float -100
“filterByName” The name must contain this name prefix. This filter is case-sensitive. When left blank, the filter will not be applied. Text “”
“filterByService” The peripheral must advertise this service. Only UUID values (not aliases) are allowed. When left blank, the filter will not be applied. Text “”
“filterByVendorID” Perform a manufacturer-specific discovery. This is more reliable than filtering by name (since names may be changed or not advertised). When set to “any”, the filter will not be applied. Integer or “any” “any”
“filterByConnectability” Set this to “connectable” to search only for connectable peripherals. When set to “notConnectable”, plug-in searches only for peripherals that cannot be connected (this can be useful when looking for Bluetooth beacons). When set to “any”, the filter will not be applied. “connectable”, “notConnectable”, or “any” “any”
“obsoleteAfter” After which time a discovery will be discarded as obsolete (in seconds). Float or “never” “never”
“onDiscovery” Script which will be scheduled every time that a new device satisfying filters is discovered. This is also triggered when a peripheral is rediscovered after being invisible for time specified by obsoleteAfter. Script receives UUID of the discovered device as a parameter. When left blank, no script will be scheduled. Text “”

Result

Returns 0 on success and ? on error. Use SBLE_Get ("devices") to display a discovery snapshot at any time during or after the scan, or use SBLE_Get ("lastError") to identify the error.

Example 1

    SBLE_StartScan

Start the scan with default options.

Example 2

    SBLE_StartScan ("stopAfter=120" &  & "minRSSI=-50" &  & "filterByName=")

Perform a scan with automatic stop after two minutes. Filter out discoveries with RSSI (Received Signal Strength Indicator) below -50. Filtering by name and vendor id will not be applied.

Example 3

    SBLE_StartScan (
        List( 
            "filterByName=" & "iPad" ;
            "filterByVendorID=" & "76" ;
            "stopAfter=" & "" ;
            "onDiscovery=" & "updateDeviceTable" ;
        )
    )

where

# updateDeviceTable script
Set Variable [ $UUID ; Value: Get( ScriptParameter ) ]
# insert new device into the database...

This scans for Apple devices with a name that begins with “iPad”. The updateDeviceTable script will be scheduled on each discovery. The scan will run until stopped manually with SBLE_StopScan or until app termination.

Example 4

    SBLE_StartScan ("filterByService=FE07")

Search for peripherals which advertise a service "FE07".

SBLE_StopScan

Stop current scan. This does not discard the results of a previous scan (until a new scan is performed).

Result

Returns 0 on success and ? on error. Use SBLE_Get ("lastError") to identify the error.

SBLE_Connect ( deviceID { ; options } )

Connects a peripheral device. Here, deviceID can be either UUID or a device name. In case of latter, plugin will try to match it with respect to known devices. Options is in the form of text field separated by ¶.

Optional parameters

Parameter Description Accepted values Default
“onDisconnect” This can specify name of a script which will be scheduled in the event of connection loss. (It does not matter which side closed the connection or if it was lost due to environmental factors. However, it will not be called on failed connection attempt. In such case, it is treated as though the connection never existed.) Text ""
“onDiscoverServices” Schedule this script when services are discovered. Script receives UUID of the relevant device (for which services were discovered) as a parameter. Text ""
“onDiscoverCharacteristics” Schedule this script when characteristics are discovered. Script receives UUID of the relevant device and the service (for which characteristics were discovered) as a parameter. Text ""
“timeout” Connection timeout in seconds. Float 3

Result

Returns 0 on success and ? on error. Use SBLE_Get ("lastError") to identify the error.

Limitation

  1. SBLE plugin does not allow to connect a device as central and peripheral simultaneously.
  2. Due to internal workings of BLE, there is an automatic disconnection after one minute, unless local device subscribes for a characteristic.

Example 1

    SBLE_Connect ( "E3720EBF-CAAD-487A-83D1-73353A904F42" ; "onDisconnect=displayWarning" )

Connect a device with the specified UUID. Run displayWarning script on disconnection. The script can look as follows:

# displayWarning
Set Variable [ $UUID ; Value: Get( ScriptParameter ) ]
# show custom dialog that informs user about the disconnection...

Example 2

    SBLE_Connect ( "Peripheral A" ; "timeout=5" )

Connect to a device named “Peripheral A” within 5 second timeout.

Example 3

    SBLE_Connect ( 
        "Peripheral B" ; 
        List(
            "onDiscoverServices=HandleDiscoveredServices" ;
            "onDiscoverCharacteristics=HandleDiscoveredCharacteristics"
        ) 
    )

Connect to a device named “PeripheralB”. Handle discovery of services and characteristics with callbacks.

SBLE_Disconnect ( deviceID )

Disconnects a peripheral device.

Result

Returns 0 on success and ? on error. Use SBLE_Get ("lastError") to identify the error.

Limitation

Note that SBLE_Disconnect cannot be used on peripheral to disconnect a central device. This is because, in Bluetooth Low Energy, only the central controls the connection lifecycle. You can, however, stop serving requests. To this end, either remove your local profile or decrease authorization of selected device.

Example 1

    SBLE_Disconnect ( "Peripheral A" )

Disconnect the device named “Peripheral A” using default timeout.

SBLE_StartAdvertising ( { options } )

This step is necessary whenever you want to connect this device as a peripheral. Runs on an asynchronous thread.

Optional parameters

Parameter Description Accepted values Default
“displayName” Under what name the device will appear when scanned. When unset, the name will be hidden. Text “”
“stopAfter” Stop advertising after this time (in seconds). Float or “never” 60

Result

Returns 0 on success and ? on error. Use SBLE_Get ("lastError") to identify the error.

How to prevent unauthorized connections

In classic BLE, you cannot preemptively refuse a connection request. However, when defining the profile, it is possible to set some or every characteristic as protected, so that the connected central cannot use them (read, subscribe or write) until authorized by the peripheral via

    SBLE_Set ( "authorization" ; deviceID ; level )

(see SBLE_Set). This can be used in combination with a single unprotected characteristic with a write property (user login).

Example

    SBLE_StartAdvertising ( "displayName=Peripheral B" &  & "stopAfter=never")

SBLE_StopAdvertising

Stops the background advertising.

Result

Returns 0 on success and ? on error. Use SBLE_Get ("lastError") to identify the error.

SBLE_Get ( selector { ; deviceID } )

Function that gets some information but does not change the state (with the possible exception of last error). This function reads locally stored values. Therefore, it should be fast and does not need timeout.

Parameter values for selector

Selector Description
“status” Returns info about the state of this device in JSON.
Or, when deviceID is provided, the state of of that connected or discovered device.
“devices” Get a JSON with a snapshot of available devices resulting from a scan. (Returns error when no scan was ever performed).
“connections” Get a list with UUIDs of all connected devices separated by ¶.
“remoteProfile” Reveal all characteristics for a connected peripheral specified by deviceID. When available, it will also show standard human-readable aliases.
“localProfile” Show all characteristics of this device (when used as a peripheral). Output is the JSON which was set by the last successful SBLE_Set ( "localProfile" ) function call.
“helperPort” Show the port that the plug-in uses to communicate with helper. This works only on macOS. The port should match the one that Helper App is listening on, otherwise the plug-in will not work.
“inlineDocumentation” On desktop version, this show whether inline documentation for plug-in functions is on.
“defaultTimeout” Returns the default timeout in seconds, which is 3 unless changed by SBLE_Set ( "defaultTimeout" ; ... ).
“defaultFormat” Returns the default format, which is “UTF-8”, unless changed by SBLE_Set ( "defaultFormat" ; ... ).
“lastError” Get the error code from the last plugin function call.
“lastErrorMessage” Get the error message from the last plugin function call.

Result (status)

The local status JSON has the following structure:

{
    "bluetooth" : String,
    "isScanning" : Boolean,
    "isAdvertising" : Boolean
}

Possible values of bluetooth status are:

If deviceID (of peripheral or central device) is specified, functions returns remote profile JSON such as:

{
    "UUID" : String,
    "name" : String,
    "relationship" : String,
    "authorizationLevel" : Number,
    "subscribedFor" : [
        String,
        ...
    ]
}

Possible values of relationship are:

Array subscribedFor will contain UUIDs of all local characteristics the device is subscribed for.

Result (devices)

When selector is "devices", the output JSON is:

[
    {
        "UUID" : String,
        "name" : String,
        "RSSI" : Number,
        "timestamp" : String,
        "connectable" : Boolean,
        "serviceUUIDs" : [
            String,
            ...
        ],
        "serviceData" : [
            String: String,
            ...
        ]
    },
    ...
]

UUID, RSSI and timestamp are always present. Other fields can be missing when not advertised by the peripheral. Please note that peripherals may not advertise all their services (they rarely do). To get all available services, you must first connect the peripheral and then call SBLE_Get with remoteProfile selector.

Result (connections)

When selector is "connections", the output is a return-separated list:

UUID1
UUID2
...
Result (remoteProfile)

Remote profile selector returns a JSON like this:

[
    {
        "UUID" : String,
        "alias" : String,
        "characteristics" : [
            {
                "UUID" : String,
                "alias" : String,
                "properties" : String
            }
        ]
    },
    ...
]

Alias can be missing if the service or characteristic UUID is non-standard or unknown to the plug-in. The value "properties" is any combination of keywords

separated by |.

Result (localProfile)

Local profile selector returns same JSON as previously provided by the last successful set function call.

Result (lastError and lastErrorMessage)

Last error and last error message return a number (see errors) or a string respectively.

Example 1

    SBLE_Get ( "status" )

returns a JSON such as:

{
    "bluetooth" : "poweredOn",
    "isScanning" : false,
    "isAdvertising" : false
}

Example 2

    SBLE_Get ( "status" ; "Peripheral A" )

returns a JSON such as:

{
    "UUID" : "E3720EBF-CAAD-487A-83D1-73353A904F42",
    "name" : "Peripheral A",
    "relationship" : "connectedPeripheral",
    "authorizationLevel" : 0,
}

Example 3

    SBLE_Get ( "status" ; "9AE0058D-60AA-42EC-9B46-52BEB9C31038" )

returns a JSON such as:

{
    "UUID" : "9AE0058D-60AA-42EC-9B46-52BEB9C31038",
    "name" : "Central A",
    "relationship" : "subscribedCentral",
    "subscribedFor" : [ 
        "F5450356-8678-9D5F-ED54-8DAC2A6D366C"
     ],
    "authorizationLevel" : 1,
}

Example 4

    SBLE_Get ( "devices" )

returns a JSON such as:

[
  {
    "UUID" : "7D86B3EF-AC3F-C78B-A2DF-F978297654BD",
    "name" : "S16 AC77 LE",
    "vendorID" : 1447,
    "RSSI" : -62,
    "connectable" : true,
    "serviceUUIDs" : [
      "FE07"
    ],
    "timestamp" : "24.08.2026, 9:36:42"
  },
  {
    "UUID" : "F5450356-8678-9D5F-ED54-8DAC2A6D366C",
    "name" : "yunmi.kettle.v2",
    "RSSI" : -76,
    "connectable" : true,
    "serviceData" : {
      "FE95" : "712013014ecc3e2deb497c09051002001f"
    },
    "timestamp" : "24.08.2026, 9:36:42"
  },
  {
    "UUID" : "4A3A92E0-87B6-7592-7CD9-65D5B25F980B",
    "vendorID" : 76,
    "RSSI" : -60,
    "connectable" : false,
    "timestamp" : "24.08.2026, 9:36:42"
  }
]

Note that the name is missing in the third entry because it is not advertised by the peripheral.

Example 5

    SBLE_Get ( "connections" )

returns a text field such as:

E3720EBF-CAAD-487A-83D1-73353A904F42
22C94316-884B-4526-B6B4-D8F5649F8E4D
9AE0058D-60AA-42EC-9B46-52BEB9C31038

Example 6

    SBLE_Get ( "remoteProfile" ; "peripheral A" )

Shows all characteristics in a JSON. The typical output will look like this:

[
    {
        "UUID" : "180A",
        "alias" : "Device Information",
        "characteristics" : [
            {
                "UUID" : "2A29",
                "alias" : "Manufacturer Name String",
                "properties" : "read"
            }
        ]
    },
    {
        "UUID" : "B3E84E34-4081-4AB0-ABCD-D691F1BF60DD",
        "characteristics" : [
            {
                "UUID" : "9AD76D02-BA20-4ECF-B059-FD5AE10F8CA9",
                "properties" : "write|notify"
            }
        ]
    }
]

SBLE_GetLocalCharacteristic ( serviceUUID ; characteristicUUID { ; format } )

Get value of a local characteristic. Format defines how output is converted from binary. It does not matter if the characteristic has read property or not.

Result

Returns the value of that characteristic.

Example

    SBLE_GetLocalCharacteristic ( "5A283830-8759-446B-A845-564D090806D3" ; "3A345569-D942-4A42-8BFA-A2755809B1DD" ; "UTF-8" )

Gets the binary data of a local characteristic and converts it to FileMaker Text using UTF-8 encoding.

SBLE_Set ( selector { ; deviceID } ; value )

Function that sets some locally stored value. It does not send any information to other devices. Therefore, it should be fast and does not need timeout.

Parameter values for selector

Selector Description Accepted Values
“localProfile” This function defines services and characteristics used by this device when connected as a peripheral. It must be called before Advertising. Calling this during advertising will return error. JSON
“authorization” Authorize connected central specified by deviceID to access characteristics marked as protected, or revoke such a permission. Value should specify the authorization level.
Here, deviceID must be UUID. Authorization cannot be set for a device name.
Number
“defaultFormat” Changes the default format. Default format is "UTF-8", unless specified. “UTF-8”, “UInt8” or “Hex”
“defaultTimeout” Changes the default timeout in seconds. Default timeout is 3 seconds, unless specified. Float
“helperPort” On desktop version, this changes the port which the plug-in uses for communication with the helper (default is 24026). Integer in range from 1024 to 65535
“inlineDocumentation” On desktop version, this toggles inline documentation. “on” or “off”

The localProfile selector accepts JSON in this format:

[
    {
        "UUID"  : String,
        "characteristics" : [
            {
                "UUID" : String,
                "properties" : String,
                "protection"  : Number,
                "afterRead" : String,
                "afterWrite" : String,
                "afterSubscribe" : String,
                "afterUnsubscribe" : String,
                "format" : String,
                "encrypted" : Bool
            },
            ...
        ],
        ...
    }
]

where properties define the admissible commands of a connected central (possible values are "read", "write", "writeWithoutResponse" and "notify", or any combination thereof separated by "|" ). The remaining parameters are optional. With protection, you can specify the minimum authorization level that connected central needs to read or write this characteristic (default value is 0). Note that a connected central can always subscribe for notifications. However, it will not receive any notifications unless authorized. With afterRead, afterWrite, afterSubscribe and afterUnsubscribe you can specify a script which will be scheduled after a central performs a successful read, write or (un)subscribe command respectively. In any case, the script will receive two parameters separated by ¶: the UUID of the central device and the current characteristic data, converted to a text variable using the specified format. Lastly, with "encrypted": true, you can enforce encrypted communication between the devices (using AES-128 cipher), which prevents eavesdropping. Combination of authorization levels and encryption allows you to achieve level 3 security according to the GATT specification. The downside is that pairing must be approved, requiring one additional step from the user, and some older devices may not support this.

Note that, when writing the JSON manually in a text field, FileMaker will sometimes automatically replace standard double quotes ("") with different localized symbols that look nearly identical but make the JSON corrupted. To circumvent this problem, it is recommended to build the parameter using JSON functions.

Result

Returns 0 on success and ? on error. Use SBLE_Get ("lastError") to identify the error.

Example 1

    SBLE_Set ("localProfile" ; "Parameter")

where Parameter is

[    
   {
        "UUID"  : "12345678-1234-1234-1234-1234567890AB",
        "characteristics" : [
            {
                "UUID" : "12345678-1234-1234-1234-1234567890AF",
                "properties" : "notify",
                "afterSubscribe" : "After Subscribe",
                "afterUnsubscribe" : "After Unsubscribe",
                "protection" : 0       
            },
            {
                "UUID" : "12345678-1234-1234-1234-1234567890AC",
                "properties" : "read",
                "afterRead" : "After Read",
                "protection" : 1,
            },
            {
                "UUID" : "12345678-1234-1234-1234-1234567890AD",
                "properties" : "write|writeWithoutResponse",
                "afterWrite" : "After Write",
                "protection" : 2,
            }
        ]
    }
]

will setup the plug-in to serve as a peripheral with one service and three characteristics: for reading, writing and notifying. This assumes that “After Read” etc. are names of scripts that exist prior to the function call.

SBLE_SetLocalCharacteristic ( serviceUUID ; characteristicUUID ; value { ; format } )

Set characteristic value on this device (use in peripheral mode). All subscribed centrals will be automatically notified about this change. Format defines how input is converted into binary. It does not matter if the characteristic has write property or not.

Result

Returns 0 on success and ? on error. Use SBLE_Get ("lastError") to identify the error.

Example

    SBLE_SetLocalCharacteristic ( "5A283830-8759-446B-A845-564D090806D3" ; "3A345569-D942-4A42-8BFA-A2755809B1DD" ; "new value" ; "UTF-8")

SBLE_Subscribe ( deviceID ; serviceUUID ; characteristicUUID ; onNotify { ; format { ; timeout } } )

Subscribe for notifications from peripheral. The device must be connected. Returns error when already subscribed or characteristic does not exist. Notifications will trigger onNotify script with four parameters separated by ¶: the remote device UUID, the service UUID, the characteristic UUID and the updated value. Returns 0 on success and ? on error. Use SBLE_Get ("lastError") to identify the error.

Example 1

SBLE_Subscribe ( "peripheral A" ; "180F" ; "2A19" ; "OnBatteryLevelNotify" ; "UInt8" ; 3 )

where

# OnBatteryLevelNotify script
Set Variable [ $params ; Value: Get( ScriptParameter ) ]
Set Variable [ $deviceUUID ; Value: GetValue( $params ; 1 ) ]
Set Variable [ $serviceUUID ; Value: GetValue( $params ; 2 ) ]
Set Variable [ $characteristicUUID ; Value: GetValue( $params ; 3 ) ]
Set Variable [ $batteryLevel ; Value: GetValue( $params ; 4 ) ]
# update battery level in GUI...

This subscribes for a characteristic on peripheral for checking the battery level. This assumes the characteristic has “notify” property. Here, the 3 second timeout is for to the subscription itself. It does not affect notifications received from the peripheral.

Example 2

SBLE_Subscribe ( "peripheral A" ; "180F" ; "2A19" ; "" ; "" ; 3 )

Unsubscribes from the service. (In this special case, the format parameter is ignored and can be empty.)

SBLE_Read ( deviceID ; serviceUUID ; characteristicUUID { ; format { ; timeout } } )

Reads characteristic from a peripheral. The device must be connected and the characteristic must have “read” property. Format defines how output is converted from binary.

Result

Waits for response and returns the value of that characteristic, or ? in case of error.

Example

SBLE_Read ( "peripheral A" ; "180A" ; "2A29" ; "UTF-8" )

Asks peripheral for manufacturer name string.

SBLE_Write ( deviceID ; serviceUUID ; characteristicUUID ; value { ; format { ; timeout } } )

Writes characteristic on a peripheral. The device must be connected and the characteristic must have “write” property. Format defines how input is converted to binary. When timeout is zero or "dontWait", write operation will not wait for response. This makes it succeed immediately but you will not be informed in case of write error. For this to work, the characteristic need to have “writeWithoutResponse” property.

Result

Returns 0 on success and ? on error. Use SBLE_Get ("lastError") to identify the error.

Example

SBLE_Write ( "peripheral B" ; "4922B7B5-1215-4D1F-96E2-C87280C4B9C8" ; "E06E4A33-ED1D-4EB7-A5F5-27BAF31AD00E" ; "48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21" ; "Hex" )

Performs write operation on peripheral B. Passes the binary data to the plug-in as string using Hex representation.

About format parameter

Data between devices is sent in binary form. Format defines how FileMaker values are converted to and from the binary form. Supported formats are:

Format Description
UTF-8 Sending text encoded as UTF-8 without BOM. (Default)
UInt8 Interpret binary data as an unsigned 8 bit integer (0-255). Exactly 8 bits are transferred.
Hex Binary data is interpreted as hexadecimal digits. Every character can be one of “0123456789ABCDEF” and represents 4 bits of binary data.

Authorization levels

Authorization levels allow to secure your peripheral device against unauthorized connection. Each time a central device connects, it’s authorization level is set to 0. You can change the level from your plug-in instance (acting as peripheral) using SBLE_Set. A connected central is unable to access characteristics with protection level higher than its authorization level. It’s up to the user what meaning is associated with each level, but a typical scheme is:

Level Description
0 unauthenticated
1 authenticated
2 trusted
3 admin

Use Case Examples

Using iPhone to control skID RFID reader

Firstly, we start scanning using

    SBLE_StartScan

After a while, we read the scan result via

    SBLE_Get ( "devices" )

and obtain an output which looks like this:

[
    {
        "UUID" : "F256FEA8-B0F7-43C8-9F8F-AE1E6821AA7C",
        "name" : "skID-20370018",
        "RSSI" : -21,
        "timestamp" : "15.1.2026 14:53:56"
    },
    {
        "UUID" : "1D9AF508-54EC-4F37-A98F-D5C358AB11E6",
        "RSSI" : -43,
        "timestamp" : "15.1.2026 14:54:21"
    }
]

Then, we connect to skid via:

    SBLE_Connect ( "skID-20370018" )

The return value is 0, which means that connection was successful. We can stop scanning now because we no longer need it. (This could also be done before connecting.)

    SBLE_StopScan

Now, we will look at services offered by skid. To this end, we call

    SBLE_Get ( "remoteProfile" ; "skID-20370018" )

and will obtain a result such as:

[
  {
    "alias" : "Device Information",
    "UUID" : "180A",
    "characteristics" : [
      {
        "properties" : "read",
        "alias" : "Manufacturer Name String",
        "UUID" : "2A29"
      }
    ]
  },
  {
    "alias" : "Battery",
    "UUID" : "180F",
    "characteristics" : [
      {
        "UUID" : "2A19",
        "properties" : "read",
        "alias" : "Battery Level"
      }
    ]
  },
  {
    "alias" : "542EE6C2-EDD1-11EA-ADC1-001999BED156",
    "UUID" : "542EE6C2-EDD1-11EA-ADC1-001999BED156",
    "characteristics" : [
      {
        "properties" : "notify",
        "alias" : "542EE91A-EDD1-11EA-ADC1-001999BED156",
        "UUID" : "542EE91A-EDD1-11EA-ADC1-001999BED156"
      },
      {
        "properties" : "writeWithoutResponse",
        "alias" : "542EEC3A-EDD1-11EA-ADC1-001999BED156",
        "UUID" : "542EEC3A-EDD1-11EA-ADC1-001999BED156"
      }
    ]
  }
]

To read the battery level, we would call

    SBLE_Read ( "skID-20370018" ; "180F" ; "2A19" ; "UInt8" )

This would return some value, like 2. To know how to interpret the data, we need to look at the Bluetooth specification. Some services are manufacturer-dependant, in which case we need to refer to the technical documentation. In this example, skID uses easy2read Protocol. To control the reader, we would first subscribe to the output channel by:

    SBLE_Subscribe ( 
        "skID-20370018" ; 
        "542EE6C2-EDD1-11EA-ADC1-001999BED156" ; 
        "542EE91A-EDD1-11EA-ADC1-001999BED156" ;
        "datahandler" ;
        "Hex"
    )

and then send a command to perform a rapid inventory scan:

    SBLE_Write ( 
        "skID-20370018" ; 
        "542EE6C2-EDD1-11EA-ADC1-001999BED156" ; 
        "542EEC3A-EDD1-11EA-ADC1-001999BED156" ;
        "8001000000005358002100000008000100130000000F00FB536F757263655F3000" ;
        "Hex" ;
        0
    )

The response is in form of hex encoded raw bytes which needs to be parsed in the datahandler script.

Two-sided communication between two iOS devices

Firstly, we need to setup the Peripheral by:

    SBLE_Set ( "localProfile" ; Table::Profile )

where Table::Profile is the following text field:

[
    {
        "UUID"  : "5A283830-8759-446B-A845-564D090806D3",
        "characteristics" : [
            {
                "UUID" : "3A345569-D942-4A42-8BFA-A2755809B1DD",
                "properties" : "read|notify",
            },
            {
                "UUID" : "E3E79D2F-F6FE-453E-AAD9-BD3411084BAD",
                "properties" : "write|writeWithoutResponse",
                "afterWrite" : "receiveMessageFromCentral"
            }
        ]
    }
]

This defines a custom communication service with two characteristics: one for incoming and one for outgoing channel. The UUIDs in this example can be generated using the native FileMaker function Get( UUID ).

Next, we call

    SBLE_StartAdvertising ( "displayName=TestDevice" )

which makes the device visible. Now, on Central, we scan, find the TestDevice and connect it as in the previous example. Afterwards, we subscribe the incoming channel on peripheral by

    SBLE_Subscribe ( 
        "TestDevice" ; 
        "5A283830-8759-446B-A845-564D090806D3" ; 
        "3A345569-D942-4A42-8BFA-A2755809B1DD" ; 
        "receiveMessageFromPeripheral"
    )

This completes the communication setup. Now, Central can send a message to Peripheral using

    SBLE_Write ( 
        "TestDevice" ; 
        "5A283830-8759-446B-A845-564D090806D3" ; 
        "E3E79D2F-F6FE-453E-AAD9-BD3411084BAD" ; 
        "Hello! I am Central!" ;
        "UTF-8";
        0
    )

To send a message from Peripheral to Central, use

    SBLE_SetLocalCharacteristic (
        "5A283830-8759-446B-A845-564D090806D3" ; 
        "3A345569-D942-4A42-8BFA-A2755809B1DD" ;
        "Hello! I am Peripheral!"
    )

Error codes

Code Description Details
0 No error All requested actions were successful.
-4 Not implemented The function is not implemented on this platform.
-10 Bluetooth error Bluetooth is currently unavailable. It might be turned off, resetting or your app does not have correct permissions.
-11 Unknown device The UUID or device name does not correspond to any connected or discovered device.
-12 Multiple devices Operation cannot be performed because more than one device has the same name. You must specify the device with UUID instead.
-13 Unknown characteristic The specified characteristic is unknown. It may take some time before services of a connected peripheral are discovered.
-14 No data Tried to get, set, read or work with void data.
-15 Connection error Could not connected to a peripheral.
-16 Read error Could not read from a characteristic. Maybe it lacks “read” property or you do not have correct permissions.
-17 Write error Could not write to a characteristic. Maybe it lacks “write” or “writeWithoutResponse” property or you do not have correct permissions. If data is too long, consider splitting it into smaller packets.
-18 Subscribe error Subscribing was denied by peripheral. Maybe it lacks “notify” property or you do not have correct permissions.
-19 Notify error Local characteristic was set but plug-in could not notify subscribed centrals.
-30 Not connected Operation requires that the selected device is connected.
-31 Not scanning Operation requires that scanning is in progress.
-32 Not advertising Operation requires that advertising is in progress.
-40 Already connected Plug-in requires that you disconnect if you want to connect with different parameters.
-41 Already scanning Plug-in requires that you stop scanning if you want to start another scan with different parameters.
-42 Already advertising Plug-in requires that you stop advertising if you want to advertise with different parameters.
-50 Parameter error Wrong number, type, value or order of parameter(s). Please check parameters against the documentation again.
-80 Unknown error Unexpected (probably system related) error occurred.
-100 Timeout error Operation was running too long. This happens when connected device is unresponsive or when timeout parameter is too small.
-300 Helper error On desktop version, this error means that the plug-in did not receive a valid response from helper app. Check that the helper app is installed and the helper port is configured correctly.
24001 Demo mode expired If you want to keep using the Plug-In, you must register it or buy it for particular environment.
24002 Product expired Trial period is over. If you want to keep using the product, you must buy it for particular environment.
24003 SN limit was met The serial number is already registered on too many computers.
24004 Product is dead The product expired and cannot be used any more. Please download the new version from 24U Software.
24005 Invalid serial number Serial number you entered is not valid.
24006 Activation failed Activation failed probably due to some network error. Please, check your connection to the internet and try again later.
24007 Deactivation failed Deactivation failed probably due to some network error. Please, check your connection to the internet and try again later.
24008 Unknown serial number The given serial number cannot be used for the current product. It has been stored so that other product can try to use it.
24009 Blacklisted serial number The given serial number has been blacklisted and cannot be used anymore. Please, contact 24U Support if you need more information.